﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Windows.Forms;


namespace simDC
{
    public class BGC
    {
        private static Processor p = Processor.P;
        public static List<string> microcode = new List<string>();
        public static Dictionary<String, int> microcodeLabel = new Dictionary<String, int>();
        public ListView listMicroCode = null;
        public int contorfaza = 1;
        MicroInstruction m = null;
        public ListView instrText = null;

        int microInstructionIndex = 1; // parcurge nesecvential microcodul

        public BGC(ListView listViewMicrocode, ListView instructionText)
        {
            listMicroCode = listViewMicrocode;
            instrText = instructionText;
          
        }
        public void Reset() 
        {
            microInstructionIndex = 0;
            contorfaza = 1;
            p.bpo = true;
        }

        public void LoadInstructionText()
        {
            instrText.Items.Clear();
            foreach (KeyValuePair<int, string> instructPair in Parser.instructionText) 
            {
                string s ="nu";
                s = (from k in Parser.labelDictionary where (k.Value == instructPair.Key) select k.Key).FirstOrDefault();
                string[] localval = {"0x"+instructPair.Key.ToString("X3"),s, instructPair.Value};
                ListViewItem lvi = new ListViewItem(localval);
                instrText.Items.Add(lvi);
            }
           instrText.Items[0].Selected = true;
        }

      

        public int LoadMicrocode(String microcodeFileName)
        {
            microInstructionIndex = 0;
            microcode.Clear();
            microcodeLabel.Clear();

            try
            {
                System.IO.StreamReader myFile = new System.IO.StreamReader(microcodeFileName);
                string line;
                char[] separator = { ',' };

                while ((line = myFile.ReadLine()) != null)
                {
                    if (line != "")
                    {
                        string[] values = line.Split(separator, StringSplitOptions.RemoveEmptyEntries);
                        string[] more = new string[values.Length + 1];
                        values.CopyTo(more, 1);
                        more[0] = "0x" + microInstructionIndex.ToString("X3");
                        ListViewItem lvi = new ListViewItem(more);
                        listMicroCode.Items.Add(lvi);


                        if (values[0].CompareTo("NONE") != 0 && values[0] != "")
                        {
                            microcodeLabel.Add(values[0], microcode.Count);
                        }
                        microcode.Add(line);
                        microInstructionIndex++;
                    }
                }

                listMicroCode.Items[0].Selected = true;
                myFile.Close();
            }

            catch (Exception e)
            {
                microInstructionIndex = 0;
                return -1;
            }
            finally 
            {
                microInstructionIndex = 0;
            }

            return 1;


           
        }

        public void ExecuteStep(ListView l)
        {
           
           // if (BGC.microcodeLabel.ContainsKey("HALT"))
           // if (microInstructionIndex != microcodeLabel["HALT"])
            //{
             
            if(p.bpo)
            {
                switch (contorfaza)
                {
                    case 1:

                            m = new MicroInstruction(microcode[microInstructionIndex], microInstructionIndex, l);
                            listMicroCode.Items[microInstructionIndex].Selected = true;
                            contorfaza++;
                            for (int i = 0; i < instrText.Items.Count; i++)
                                if (instrText.Items[i].SubItems[0].Text == ("0x" + (p.PC - 2).ToString("X3")))
                                { instrText.Items[i].Selected = true; break; }

                            break;
                        
                    case 2:
                    case 3:
                    case 4:
                    case 5:
                    case 6: m.Execute(contorfaza++); break;
                    case 7: microInstructionIndex = m.NextAddress(microInstructionIndex); contorfaza = 1; break ;
                   
                }               
           
            Simulator.updateArchitecture.Set();
           
                    
                   
                }
               
            
        }

        public void Run(ListView l) 
        {
            while (p.bpo)
            {
                ExecuteStep(l);
            }
            MessageBox.Show("Completed run!", "Run",
                   MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

    }

    public class MicroInstruction
    {
        private static Processor p = Processor.P;
        public string[] values = null;
        int adr = 0;
        string succesor = null;
        ListView microCodeView = null;

        public MicroInstruction(String microInstruction, int a, ListView microCode)
        {
            microCodeView = microCode;
            adr = a;
            char[] separator = {',' };
            string label1 = null;
            values = microInstruction.Split(separator, StringSplitOptions.RemoveEmptyEntries);
            if (values.Length != 8)
                throw new ArgumentException();

            microCode.Items.Clear();
            string[] more = new string[values.Length + 1];
            values.CopyTo(more, 1);
            more[0] = "0x" + a.ToString("X3");
            ListViewItem lvi = new ListViewItem(more);
            microCode.Items.Add(lvi);

            
            microCodeView.Items[0].UseItemStyleForSubItems = false;
            microCodeView.Items[0].SubItems[2].BackColor = Color.DarkBlue;
            microCodeView.Items[0].SubItems[2].ForeColor = Color.White;

            label1 = values[0];
            
            p.ComputeSBUS(values[1]);
            /*
            p.ComputeDBUS(values[2]);
            p.ComputeALU(values[3]);
            p.ComputeRBUS(values[4]);
            p.ComputeOTHER(values[5]);
            p.ComputeMEM(values[6]);
            succesor = values[7];
            */

            // mai trebuie          
        }
        public void Execute(int a) 
        {
            if(a>1 && a<7)
            switch (a) 
            {
                case 2: p.ComputeDBUS(values[2]);                         
                       // microCodeView.Items[0].UseItemStyleForSubItems = false;
                        microCodeView.Items[0].SubItems[2].BackColor = Color.White;
                        microCodeView.Items[0].SubItems[2].ForeColor = Color.Black;
                        microCodeView.Items[0].SubItems[3].BackColor = Color.DarkBlue;
                        microCodeView.Items[0].SubItems[3].ForeColor = Color.White;  break;
                case 3: p.ComputeALU(values[3]); 
                        microCodeView.Items[0].SubItems[3].BackColor = Color.White;
                        microCodeView.Items[0].SubItems[3].ForeColor = Color.Black;
                        microCodeView.Items[0].SubItems[4].BackColor = Color.DarkBlue;
                        microCodeView.Items[0].SubItems[4].ForeColor = Color.White;  break;
                case 4: p.ComputeRBUS(values[4]); 
                        microCodeView.Items[0].SubItems[4].BackColor = Color.White;
                        microCodeView.Items[0].SubItems[4].ForeColor = Color.Black;
                        microCodeView.Items[0].SubItems[5].BackColor = Color.DarkBlue;
                        microCodeView.Items[0].SubItems[5].ForeColor = Color.White;  break;
                case 5: p.ComputeOTHER(values[5]);
                        microCodeView.Items[0].SubItems[5].BackColor = Color.White;
                        microCodeView.Items[0].SubItems[5].ForeColor = Color.Black;
                        microCodeView.Items[0].SubItems[6].BackColor = Color.DarkBlue;
                        microCodeView.Items[0].SubItems[6].ForeColor = Color.White;  break;
                case 6: p.ComputeMEM(values[6]); 
                        microCodeView.Items[0].SubItems[6].BackColor = Color.White;
                        microCodeView.Items[0].SubItems[6].ForeColor = Color.Black;
                        microCodeView.Items[0].SubItems[7].BackColor = Color.DarkBlue;
                        microCodeView.Items[0].SubItems[7].ForeColor = Color.White;  break;
            }
            
        }
        public int NextAddress(int adresa)//, RichTextBox rtb)
        {
            microCodeView.Items[0].SubItems[7].BackColor = Color.White;
            microCodeView.Items[0].SubItems[7].ForeColor = Color.Black;
            microCodeView.Items[0].SubItems[8].BackColor = Color.DarkBlue;
            microCodeView.Items[0].SubItems[8].ForeColor = Color.White; 

            int adr = -1;
            string microI = BGC.microcode[adresa];
            char[] separator = { ',' };
            char[] separator2 = { ' ' };
            char[] separator3 = { '+' };
            string[] values = microI.Split(separator);
            if (values[7] == "STEP")
                adr = adresa + 1;
            else
            {
                string[] vs = values[7].Split(separator2);
                if (vs[0] == "IF")
                {
                    if (ValidateG(vs[1]))
                    {
                        if (vs[2] == "JUMP")
                            if (BGC.microcodeLabel.ContainsKey(vs[3]))
                                adr = BGC.microcodeLabel[vs[3]];
                            else ;
                        else
                            if (vs[2] == "JUMPI")
                            {
                                string[] vi = vs[3].Split(separator3);
                                if (BGC.microcodeLabel.ContainsKey(vi[0]))
                                    adr = BGC.microcodeLabel[vi[0]] + Index(vi[1]);
                                else Console.WriteLine("Nu am gasit eticheta");
                            }
                            else
                                if (vs[2] == "STEP") adr = adresa + 1;
                                else ;
                    }
                    else
                    {
                        if (vs[1] == "REG")
                            if (vs[4] == "JUMP")
                                if(BGC.microcodeLabel.ContainsKey(vs[5]))
                                    adr = BGC.microcodeLabel[vs[5]] ;
                            
                        if (vs[5] == "STEP")
                            adr = adresa + 1;
   
                       /* else
                        {
                            if (vs[5] == "JUMP")
                                if (BGC.microcodeLabel.ContainsKey(vs[6]))
                                    adr = BGC.microcodeLabel[vs[6]];
                                else ;
                            else
                                if (vs[5] == "JUMPI")
                                {
                                    string[] vi = vs[6].Split(separator3);
                                    if (BGC.microcodeLabel.ContainsKey(vi[0]))
                                        adr = BGC.microcodeLabel[vi[0]] + Index(vi[1]);
                                    else if (vs[5] == "NONE")
                                        ;
                                }
                        }*/

                    }
                }
                else 
                    if (vs[0] == "JUMP")
                                if (BGC.microcodeLabel.ContainsKey(vs[1]))
                                    adr =  BGC.microcodeLabel[vs[1]];
                                else ;
                    else
                         if (vs[0] == "JUMPI")
                                {
                                    string[] vi = vs[1].Split(separator3);
                                    if (BGC.microcodeLabel.ContainsKey(vi[0]))
                                        adr =  BGC.microcodeLabel[vi[0]] + Index(vi[1]);
                                    else ;
                                }


            }
            if (adr == -1)
                Console.WriteLine("************************");//rtb.AppendText("adresa e -1");

            return adr;
            
        }

        public ushort Index(string indx)
        {
            ushort index = 0;
            switch (indx)
            {
                case "INDEX0": index = 0; break;
                case "INDEX1": index = GetMyClass(); break;
                case "INDEX2": index = (ushort)((p.IR & 0x0030) >> 2/*3*/); break;
                case "INDEX3": index = (ushort)((p.IR & 0x0C00) >> 9); break;
                case "INDEX4": index = (ushort)((p.IR & 0xF000) >> 11); break;
                case "INDEX5": index = (ushort)((p.IR & 0x1F00) >> 7); break; //salt in clasa B2
                case "INDEX6": index = (ushort)((p.IR & 0x1F00) >> 7); break; // salt in clasa B3 sau B4 - acelasi index pt ca am codficia opcode pe primii 8 biti
            }

            return index;
        }
        public ushort GetMyClass()
        {
            switch (Instruction.GetInstrType(p.IR))
            {
                case InstrType.B1: return 0;
                case InstrType.B2: return 1;
                case InstrType.B3: return 2;
                case InstrType.B4: return 3;
            }
            return 0;
        }
        public bool ValidateG(string conditie) 
        {
            // flaguri = 0000 0000 0000 VSZC
            p.g = false;
            switch (conditie) 
            {
                //aici vin succesorii testati :D
                case "B1": if (Instruction.GetInstrType(p.IR) == InstrType.B1) p.g = true; break; 
                case "B2": if (Instruction.GetInstrType(p.IR) == InstrType.B2) p.g = true; break;    
                case "C": if (((int)(p.FLAG) & 0x0001) == 0x0001) p.g = true; break;
                case "Z": if (((int)(p.FLAG) & 0x0002) == 0x0002) p.g = true; break;
                case "S": if (((int)(p.FLAG) & 0x0004) == 0x0004) p.g = true; break;
                case "V": if (((int)(p.FLAG) & 0x0008) == 0x0008) p.g = true; break;

                case "NC": if (((int)(p.FLAG) & 0x0001) == 0x0000) p.g = true; break;
                case "NZ": if (((int)(p.FLAG) & 0x0002) == 0x0000) p.g = true; break;
                case "NS": if (((int)(p.FLAG) & 0x0004) == 0x0000) p.g = true; break;
                case "NV": if (((int)(p.FLAG) & 0x0008) == 0x0000) p.g = true; break;

                case "CIL":
                    if (Instruction.GetInstrType(p.IR) == InstrType.B1)
                        if (Encodings.instructionDictionary.ContainsValue((short)(p.IR & 0xf000)) == false)
                        { p.CIL = true; p.g = true; }
                        else ;
                    else
                    {   int blah = p.IR & 0xff00;
                        if (Encodings.instructionDictionary.ContainsValue(blah) == false)
                        { p.CIL = true; p.g = true; }
                    }
                break;                  
                case "ACLOW": if (p.ACLOW) p.g = true; break;
                case "INTR":  if (p.INTR) p.g = true; break;
                case "REG":  if ((p.IR & 0x0030) == 0x0010) p.g = true; break;
            }

            
            return p.g;
        
        }
    }
}

